﻿using System.Collections.Generic;
using System.Drawing;

namespace TowerDefense_MLP
{
    public enum Consts 
	{
        OCCUPIED = -1,
	    EMPTY = 0,
        VICTORY = 1,
        DEFEATED = 2,
	}; 
    
    class Map
    {   
        #region ATTRIBUTES
        private Bitmap actualMap;
        private List<Point> wavePathPoints;
        private int[,] worldGrid;
        private int _mapID;

        #endregion

        #region METHODS

        #region Getter/Setters
        public int[,] WorldGrid
        {
            get { return worldGrid; }
            set { worldGrid = value; }
        }
        public List<Point> WavePath
        {
            get { return this.wavePathPoints; }
        }
        public Bitmap MapImage
        {
            get { return actualMap; }
            set { actualMap = value; }
        }

        #endregion

        public Map(int mapID)
        {
            this._mapID = mapID;

            // LER DO XML QUAL É O STRING DESSE ID
            CreateWolrd(mapID);
           
            //after get the correct image to display
            this.actualMap = new Bitmap(@MapsDataBase.GetImagePath(mapID));
        }

        public void updateMap()
        {
            this.actualMap.Dispose();
            this.actualMap = new Bitmap(@MapsDataBase.GetImagePath(this._mapID));
        }

        public List<Wave> GetWavesInfos()
        {
            // load waves
            List<Wave> newWaves = new List<Wave>();
            
            foreach (int[] wave in MapsDataBase.GetWavesInfos(this._mapID))
                newWaves.Add(new Wave(wave[0], wave[1]));

            return newWaves;
        }

        private void CreateWolrd(int mapID)
        {
            this.actualMap = new Bitmap(@MapsDataBase.GetImageCodePath(mapID));
            Color c;
            
            this.WorldGrid = new int[this.actualMap.Width, this.actualMap.Height];

            int startX=0, startY=0;

            for (int x = 0; x < this.actualMap.Width; x++)
            {
                for (int y = 0; y < this.actualMap.Height; y++)
                {
                    c = this.MapImage.GetPixel(x, y);
                    
                    if(c.B == 255) // azul escuro e azul claro (caminho)
                        this.WorldGrid[x, y] = (int)Consts.OCCUPIED;
                    else 
                    {
                        if (c.G == 0) // preto (caminho)
                            this.WorldGrid[x, y] = (int)Consts.OCCUPIED;
                        else
                        {
                            if (c.R == 255) // amarelo = start point
                            {
                                this.WorldGrid[x, y] = (int)Consts.OCCUPIED;
                                startX = x;
                                startY = y;
                            }
                            else // verde = vazio
                                this.WorldGrid[x, y] = (int)Consts.EMPTY;
                        }
                    }
                }
            }

            makePath(startX, startY);
        }

        private void makePath(int startX, int startY)
        {
            this.wavePathPoints = new List<Point>();
            this.wavePathPoints.Add(new Point(startX, startY));
            
            Bitmap imageAux = new Bitmap(this.MapImage);
            Color c = this.MapImage.GetPixel(startX, startY);
            int x = startX, y = startY;
            int lastX = -2, lastY = -2;
            int newX, newY;
            int[,] aux = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} };
            bool achou = false;

            do
            {
                achou = false;

                for (int i = 0; i < 7 && !achou; i++)
                {
                    newX = aux[i, 0] + x;
                    newY = aux[i, 1] + y;

                    if ( (newX >= 0) && (newX < this.MapImage.Height) &&
                         (newY >= 0) && (newY < this.MapImage.Width) &&
                         (newX != lastX) || (newY != lastY) )
                    {
                        c = imageAux.GetPixel(newX, newY);

                        if (c.R == 0 && c.B == 255) { // azul escuro = caminho OU azul claro = fim
                            imageAux.SetPixel(x, y, Color.Black);
                            lastX = x;                
                            lastY = y;
                            x = newX;
                            y = newY;
                            this.wavePathPoints.Add(new Point(x, y));
                            achou = true;
                        }
                    }
                }
            } while ( !(c.R == 0 && c.G == 255 && c.B == 255) ); // azul claro = fim
        }

        public void DrawTower(Tower newTower)
        {
            using (Graphics g = Graphics.FromImage(actualMap))
            {
                g.DrawImage(newTower.TowerImage, newTower.Position);
            }
        }

        public void AddTowerToWorldGrid(int x, int y, int towerID)
        {
            const int width = 40;
            const int height = 40;

            for (int i = x ; i < x + width ; i++)
            {
                for (int j = y ; j < y + height ; j++)
                    this.WorldGrid[i, j] = towerID;
            }
        }

        public void RemoveTowerToWorldGrid(int x, int y)
        {
            const int width = 40;
            const int height = 40;

            for (int i = x; i < x + width; i++)
            {
                for (int j = y; j < y + height; j++)
                    this.WorldGrid[i, j] = (int)Consts.EMPTY;
            }
        }

        public bool PositionIsOccupied(int x, int y)
        {
            const int delta = 20;
            int x1 = x - delta;
            int x2 = x + delta;
            int y1 = y - delta;
            int y2 = y + delta;

            if ((x1 >= 0) && (x2 < this.actualMap.Width) &&
                (y1 >= 0) && (y2 < this.actualMap.Height) )
            {
                if (this.WorldGrid[x1, y1] == (int)Consts.EMPTY &&
                    this.WorldGrid[x1, y2] == (int)Consts.EMPTY &&
                    this.WorldGrid[x2, y1] == (int)Consts.EMPTY &&
                    this.WorldGrid[x2, y2] == (int)Consts.EMPTY)
                {
                    return false;
                }
            }
            
            return true;
        }

        public int ElementAt(int x, int y)
        {
            return this.WorldGrid[x, y];
        }

        #endregion
    }
}
